<?
	class Query
	{
		private $table;
		private $take = 0;
		private $limit = 0;
		private $order;
		private $orderField;
        private $whereQuery;
        private $fields = array();
        private $aliases = array();
        private $names = array();
        private $row = array();
        private $criteriaTemplates = array(
            'eq' => "%s = %s",
            'not' => "%s != %s",
            'lt' => "%s < %s",
            'gt' => "%s > %s",
            'like' => "%s like %s"
        );

		function __construct($table = null)
		{
			$this->table = $table;
		}

        public function build($type = "load")
        {
            switch(strtolower($type)){
                case "load":
                    $fields = count($this->fields) ? join(",", $this->fields) : "*";
                    $sql[] = sprintf("select %s from %s ", $fields, $this->table);
                    break;

                case "delete":
                    $sql[] = sprintf("delete from %s ", $this->table);
                    break;
					
				case "update":
                    $values = array();

                    foreach($this->row as $key=>$val)
                    {
						$alias = $this->alias($key);
						$val = empty($val) ? "NULL" : "'$val'";
                        if(!empty($alias)){
							$values[] = "`$alias` = $val";
                        }
					}
					
					$sql[] = sprintf("UPDATE %s SET %s ", $this->table, join(",", $values));
					break;

                case "insert":
                    $fields = array();
                    $values = array();

                    foreach($this->row as $key=>$val)
                    {
                        $alias = $this->alias($key);

                        if(!empty($alias)){
                            $fields[] = "`$alias`";
                            $values[] = empty($val) ? "NULL" : "'$val'";
                        }
                    }

                    $sql[] = sprintf("INSERT INTO %s (%s) VALUES (%s);",
                        $this->table,
                        join(",", $fields),
                        join(",", $values));

                    break;
            }

            if($type != "insert")
            {
                if(isset($this->whereQuery)){
                    $sql[] = $this->whereQuery;
                }

                if(isset($this->orderField) && $this->orderField != ""){
                    $sql[] = sprintf("ORDER BY `%s` %s", $this->orderField, $this->order);
                }

                if($this->limit > 0)
				{
					if($this->take > 0)
					{
						$sql[] = sprintf(" LIMIT %s, %s ", $this->take, $this->limit);
					}
					else
					{
						$sql[] = sprintf(" LIMIT %s ", $this->limit);
					}
                }
            }

            return join(" \n", $sql);
        }

        private function connection()
        {
            return new Connection();
        }

        public function count()
        {
            $this->fields = array();
            $this->names = array();
            $this->aliases = array();

            $this->field("count(*)")
                 ->take(0)
                 ->limit(0);

            $sql = $this->build();
            $con = $this->connection();
            $con->query($sql, $result);
            $row = mysql_fetch_row($result);
            $con->close();

            return intVal($row[0]);
        }

		public function results()
		{
            $data = array();
            $sql = $this->build();
            $con = $this->connection();
			
            $con->query($sql, $result);

            while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
            {
				if(count($this->fields))
				{
					$dataRow = array();

					foreach($this->aliases as $alias)
					{
						$dataRow[$alias] = $row[$alias];
					}
				}
				else 
				{
					$dataRow = $row;
				}
				
                $data[] = $dataRow;
            }

            $con->close();

            return $data;
		}

        public function result()
        {
            $dataRow = array();
            $sql = $this->build();
            $con = $this->connection();

            $con->query($sql, $result);

            $row = mysql_fetch_array($result, MYSQL_ASSOC);

			if(count($this->fields))
			{
				foreach($this->aliases as $alias)
				{
					$dataRow[$alias] = $row[$alias];
				}
			} 
			else 
			{
				$dataRow = $row;
			}
			
            $con->close();

            return $dataRow;
        }
		
		public function drop()
		{
            $con = $this->connection();			
			$con->query(sprintf("DROP TABLE `%s`", $this->table));
            $con->close();
		}
		
		public function clear()
		{
            $con = $this->connection();			
			$con->query(sprintf("TRUNCATE TABLE `%s`", $this->table));
            $con->close();
		}
		
		public function update($row)
		{
            $this->row = $row;
			//$this->limit(count($row));
			
			$sql = $this->build("update");
            $con = $this->connection();
			
            $con->query($sql, $result);
			$con->close();			
		}

        public function insert($row = array())
        {
            $this->row = $row;

            $con = $this->connection();
            $sql = $this->build("insert");
            $con->query($sql, $result);
            $id = mysql_insert_id();
            $con->close();

            return $id;
        }

        public function remove()
        {
            $sql = $this->build("delete");
            $con = $this->connection();
			
            $con->query($sql, $result);
            $con->close();
        }

        public function where($data)
        {
            if(!empty($data)){
                $this->whereQuery = "WHERE " . $this->criteria($data);
            }

            return $this;
        }

        private function criteria($data, $sep = "and")
        {
            if(is_string($data)){
                return $data;
            }

            $parts = array();

            foreach($data as $key=>$val)
            {
                switch(strtolower($key)){
                    case "or":
                    case "and":
                        $part = $this->criteria($val, $key);
                        $parts[] = sprintf("(%s)", $part);
                        break;

                    case "eq":
                    case "not":
                    case "lt":
                    case "gt":
                    case "like":
                        $values = $this->criteriaValues($key, $val);
                        $parts[] = join(sprintf(" %s ", $sep), $values);
                        break;

                    default:
                        $parts[] = $this->criteria($val);
                        break;
                }
            }

            return join(sprintf(" %s ", $sep), $parts);
        }

        private function criteriaValues($key, $data)
        {
            $tpl = $this->criteriaTemplates[$key];
            $parts = array();
			
            if(!is_array($data[0]))
            {
                $data = array($data);
            }

            foreach($data as $item)
            {
                $field = $this->alias($item[0]);
                $vals = $item[1];
				$sep = isset($item[2]) ? $item[2] : "or";

                if(is_array($vals))
                {
                    $vparts = array();

                    foreach($vals as $val){
						if(empty($val) && ($key == 'eq' || $key == 'not'))
						{
							$val = $key == 'eq' ? 'IS NULL' : 'IS NOT NULL';
							$tpl = "%s %s";
						} else {
							$val = "'$val'";
						}
						
                        $vparts[] = sprintf($tpl, $field, $val);
                    }

                    $parts[] = sprintf("(%s)", join(" $sep ", $vparts));
                    continue;
                }
				
				if(empty($vals) && ($key == 'eq' || $key == 'not'))
				{
					$vals = $key == 'eq' ? 'IS NULL' : 'IS NOT NULL';
					$tpl = "%s %s";
				} else {
					$vals = "'$vals'";
				}
				
                $parts[] = sprintf($tpl, $field, $vals);
            }

            return $parts;
        }

        private function alias($key)
        {
            if(isset($this->names[$key]))
            {
                return $this->names[$key];
            }

            return $key;
        }

        public function field($value, $alias = null)
        {
            $this->fields[] = empty($alias) ? $value : sprintf("%s as %s", $value, $alias);

            $alias = empty($alias) ? $value : $alias;

            $this->aliases[] = $alias;
            $this->names[$alias] = $value;

            return $this;
        }
		
		public function take($take)
		{
			$this->take = $take;
			
			return $this;
		}
		
		public function limit($limit)
		{
			$this->limit = $limit;
			
			return $this;
		}

        public function asc($field)
        {
            $this->order = 'ASC';
            $this->orderField = $this->alias($field);

            return $this;
        }

        public function desc($field)
        {
            $this->order = 'DESC';
            $this->orderField = $this->alias($field);

            return $this;
        }
	}
?>